/**
 * 业务关联类型, 关联的时候需要在业务类里添加该属性关联别的业务类
 */
package indi.zjh.dp.orm;

import indi.zjh.dp.db.Configuration;
import indi.zjh.dp.db.Session;
import indi.zjh.dp.error.RelationClassNotMatchException;
import indi.zjh.dp.error.UnsuportedFieldException;
import indi.zjh.dp.type.GSet;

import java.io.Serializable;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import org.dom4j.DocumentException;
import org.msgpack.annotation.Message;

public class Relation implements Iterable, Serializable{
	// 关联类型定义, 多对多, 一对一
	public static final int MANY = 0;
	public static final int ONE = 1;
	// 双向关联, 单向关联
	public static final int MUTUAL = 0;
	public static final int SINGLE = 1;
	protected int relation_type = 0;
	protected int link_type = 0;
	protected GSet<Long> ids = new GSet<Long>();
	protected String className;
	protected Class<?> clazz;
	// 如果关系发生变化, 则置位
	//protected boolean isChange = false;
	
	class ObjectIterator<Business> implements Iterator
	{
		protected Iterator<Long> iter;
		protected Session session;
		public ObjectIterator(Session session, Set<Long> ids)
		{
			this.iter = ids.iterator();
			this.session = session;
		}
		
		@Override
		public boolean hasNext() {
			// TODO Auto-generated method stub
			return this.iter.hasNext();
		}

		@Override
		public Business next() {
			// TODO Auto-generated method stub
			Business obj = null;
			try {
				obj = (Business)session.getById(clazz, this.iter.next().longValue());
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			return obj;
		}
	}
	
	class IdIterator<Long> implements Iterator
	{
		protected Iterator<Long> iter;
		public IdIterator(Set<Long> ids)
		{
			this.iter = ids.iterator();
		}
		
		@Override
		public boolean hasNext() {
			// TODO Auto-generated method stub
			return this.iter.hasNext();
		}

		@Override
		public Long next() {
			// TODO Auto-generated method stub
			return this.iter.next();
		}
		
	}
	
	public Relation(Class<?> cls)
	{
		this.className = cls.getName();
		this.clazz = cls;
		this.relation_type = MANY;
		this.link_type = MUTUAL;
//		try
//		{
//			this.relationClass = Configuration.getInstance().getVersion().getRelationClass(this.className);
//		}
//		catch(Exception e)
//		{
//			e.printStackTrace();
//			System.exit(1);
//		}
	}
	
	/**
	 * cls 关联的类
	 * rel_type 一对一, 一对多
	 * @param cls
	 * @param rel_type
	 */
	public Relation(Class<?> cls, int rel_type)
	{
		this.className = cls.getName();
		this.clazz = cls;
		this.relation_type = rel_type;
		this.link_type = MUTUAL;
//		try
//		{
//			this.relationClass = Configuration.getInstance().getVersion().getRelationClass(this.className);
//		}
//		catch(Exception e)
//		{
//			e.printStackTrace();
//			System.exit(1);
//		}
	}
	
	/**
	 * 
	 * @param cls
	 * @param rel_type: 一对一, 一对多
	 * @param link_type: 单向, 双向
	 */
	public Relation(Class<?> cls, int rel_type, int link_type)
	{
		this.className = cls.getName();
		this.clazz = cls;
		this.relation_type = rel_type;
		this.link_type = link_type;
	}
	
	/**
	 * 添加业务对象之间的关联
	 * @param obj
	 * @throws Exception 
	 * @throws DocumentException 
	 * @throws UnsuportedFieldException 
	 * @throws ClassNotFoundException 
	 */
	public Relation add(Business obj) throws ClassNotFoundException, UnsuportedFieldException, DocumentException, Exception
	{
		RelationClass thisRc = Configuration.getInstance().getVersion().getRelationClass(this.className);
		RelationClass rClass = Configuration.getInstance().getVersion().getRelationClass(obj.getClass().getName());
		
		if(!obj.getClass().getName().equals(this.className))
		{
			if(!thisRc.isParentOf(rClass))
			{
				throw new RelationClassNotMatchException();
			}
		}
		if(obj.getId() != 0)
		{
			// 如果是一对一关系, 先清空之前的关联
			if(this.relation_type == ONE && this.ids.size() > 0)
			{
				this.ids.clear();
			}
			
			this.ids.add(obj.getSpecId(thisRc.clazz));
			//this.isChange = true;
		}
		return this;
	}
	
	/**
	 * 移除业务对象之间的关联
	 * @param obj
	 * @throws RelationClassNotMatchException 
	 */
	public void remove(Business obj) throws RelationClassNotMatchException
	{
		if(!obj.getClass().getName().equals(this.className))
		{
			throw new RelationClassNotMatchException();
		}
		if(obj.getId() != 0)
		{
			this.ids.remove(obj.getId());
		}
		//this.isChange = true;
	}
	
	public void add(long id)
	{
		this.ids.add(id);
	}
	
	public void remove(long id)
	{
		this.ids.remove(id);
		//this.isChange = true;
	}
	
	public long[] getIds()
	{
		long[] tmpids = new long[this.ids.size()];
		Iterator<Long> iter = this.ids.iterator();
		int i = 0;
		while(iter.hasNext())
		{
			tmpids[i++] = iter.next().longValue();
		}
		return tmpids;
	}
	
	/**
	 * 清空所有的关联
	 */
	public void clear()
	{
		this.ids.clear();
		//this.isChange = true;
	}
	
	/**
	 * 判断业务对象是否和指定的业务对象关联
	 * @param obj
	 * @return
	 */
	public boolean isRelated(Business obj)
	{
		if(obj.getId() == 0)
			return false;
		return this.ids.contains(obj.getId());
	}
	
	public String getRelationClassName()
	{
		return this.className;
	}

	@Override
	public Iterator<Long> iterator() {
		// TODO Auto-generated method stub
		return new IdIterator<Long>(this.ids);
	}
	
	public Iterator<Business> iterator(Session session)
	{
		return new ObjectIterator<Business>(session, this.ids);
	}
	
	/**
	 * 获取关联的第一个节点
	 * @param session
	 * @return
	 */
	public Business get(Session session)
	{
		Iterator<Business> iter = this.iterator(session);
		if(iter.hasNext())
			return iter.next();
		return null;
	}
	
	public int getLinkType()
	{
		return this.link_type;
	}
	
	public int size()
	{
		return this.ids.size();
	}
	
	public String toString()
	{
		return this.ids.toString();
	}
	
	protected GSet<Long> getIdSet()
	{
		return this.ids;
	}

}
